﻿using LogLib;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using ComLib.ComFun;

namespace ScheduleAutoAction
{
    public class Cleaner
    {
        private static object syncState = new object();
      
        private long _dPendingFileLength = 0;

        private decimal _dPendingRecordSize;
        public string PendingRecordSize
        {
            get 
            {
                if (_dPendingRecordSize.CompareTo(0.1M) < 0)
                {
                    decimal s = (decimal)_dPendingFileLength / DiskOperator.MB;
                    s = System.Decimal.Round(s, 0);
                    return _dPendingRecordSize.ToString() + "MB";
                }
                return _dPendingRecordSize.ToString() + "GB";
            }
        }

        private List<string> listRemoveFolders = new List<string>();
        private FileStream _fs;
        private StreamWriter _streamWriter;

        private bool _bCancellTaskFlag = false;

        private ScheduleCleaningOption _option = new ScheduleCleaningOption();
        public ScheduleCleaningOption Option
        {
            get { return _option; }
            set { _option = value; }
        }

        public string PhotoSaveDirectory = @"D:\KPhoto";

        /// <summary>
        /// 当前操作行为的结果
        /// </summary>
        private string _strMessage = "";
        public string OperateMessage
        {
            get { return _strMessage; }
            set { _strMessage = value; }
        }

        private OperateStatus _status = OperateStatus.None;
        public OperateStatus Status
        {
            get{ return _status; }
        }

        private GetBooleanResultHandler GetCleaningPermit;

        private UpdateTextHandler UpdateRemoveState;

        private UpdateTextHandler UpdateTextBox;

        private Action AfterClear;

        private Action AfterQuery;

        private Action ShowWindow;

        private UpdateStatusIconHandler UpdateStatusIcon;

        public Cleaner(ScheduleCleaningOption opt)
        {
            _option = opt;
        }

        public Cleaner(ScheduleCleaningOption opt, string dir)
        {
            _option = opt;
            PhotoSaveDirectory = dir;
        }

        public void SetDelegateFun(
            GetBooleanResultHandler g0,
            UpdateTextHandler u0,
            UpdateTextHandler u1,          
            Action a0,
            Action a1,
            UpdateStatusIconHandler us)
        {
            GetCleaningPermit = g0;
            UpdateRemoveState = u0;
            UpdateTextBox = u1;
            AfterQuery = a0;
            AfterClear = a1;
           UpdateStatusIcon = us;
        }

        public void Init()
        {
            _status = OperateStatus.None;
            UpdateStatusIcon(_status);
        }

        /// <summary>
        /// 获取即将删除的目录路径列表
        /// </summary>
        /// <param name="span">与当天相隔的时间</param>
        private void GetRemoveFolders(int span)
        {
            listRemoveFolders.Clear();
            if (span <= 0)
            {
                return;
            }
            AddFolders(PhotoSaveDirectory, span);        
        }

        private void AddFolders(string dir, int span)
        {
            List<DirectoryInfo> listAllFolders = new List<DirectoryInfo>();
            DirectoryInfo di = new DirectoryInfo(dir);
            DirectoryInfo[] disMonths = di.GetDirectories();
            if (disMonths.Length > 0)
            {
                for (int i = 0; i < disMonths.Length; i++)
                {
                    DirectoryInfo[] disDays = disMonths[i].GetDirectories();
                    for (int j = 0; j < disDays.Length; j++)
                    {
                        listAllFolders.Add(disDays[j]);
                    }
                }
            }
            listAllFolders.Sort((DirectoryInfo d0, DirectoryInfo d1) => d0.CreationTime.CompareTo(d1.CreationTime));
            if (span > listAllFolders.Count)
            {
                return;
            }
            else
            {
                for (int i = 0; i < listAllFolders.Count - span; i++)
                {
                    listRemoveFolders.Add(listAllFolders[i].FullName);
                }
            }
        }

        private void OpenLogWriter()
        {
            string strFilePath = string.Format(@"{0}/clean_{1}.log", PhotoSaveDirectory, DateTime.Now.ToString("yyyyMMdd")); ;
            _fs = new FileStream(strFilePath, FileMode.OpenOrCreate, FileAccess.Write);
            _streamWriter = new StreamWriter(_fs);
            _streamWriter.BaseStream.Seek(0, SeekOrigin.End);
            _streamWriter.WriteLine("begin time: " + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:ffff"));
        }

        private void WriteLog(string val)
        {
            _streamWriter.WriteLine(val);
        }

        private void CloseLogWriter()
        {
            _streamWriter.WriteLine("end time: " + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:ffff"));
            _streamWriter.Flush();
            _streamWriter.Close();
            _fs.Close();
        }

        private bool OnPreparing()
        {
            try
            {
                if (!Directory.Exists(PhotoSaveDirectory))
                {
                    _strMessage = string.Format("未找到指定的照片目录: " + PhotoSaveDirectory);
                    Log.WriteAsync(_strMessage);
                    return false;
                }
                int span = _option.GetTimespan();
                GetRemoveFolders(span);
                if (listRemoveFolders.Count == 0)
                {
                    _strMessage = string.Format("未找到符合条件的待清理记录:{0}天以前的", span);
                    Log.WriteAsync(_strMessage);
                    return false;
                }
                _dPendingFileLength = 0;
                for (int i = 0; i < listRemoveFolders.Count; i++)
                {
                    _dPendingFileLength += DiskOperator.GetDirectorySpace(listRemoveFolders[i]);
                }
                Thread.Sleep(5000);
                _dPendingRecordSize = (decimal)_dPendingFileLength / DiskOperator.GB;
                _dPendingRecordSize = decimal.Round(_dPendingRecordSize, 3);
                if (_option.OnlyExecuteWhenOverCV)
                {
                    if (_dPendingRecordSize.CompareTo(_option.CriticalMemorySize) < 0)
                    {
                        _strMessage = string.Format("待清理记录大小为{0}GB，小于{1}GB. 因此暂不清理",
                            _dPendingRecordSize,
                            _option.CriticalMemorySize);
                        Log.WriteAsync(_strMessage);
                        return false;
                    }
                }
                _strMessage = string.Format("待清理记录大小为{0}，清理工作已经准备就绪.", PendingRecordSize);
                return true;
            }
            catch (Exception ex)
            {
                UpdateRemoveState("查询过程中发生了异常.");
                _strMessage = "查询过程中发生了异常:" + ex.Message;
                Log.WriteAsync(_strMessage);
                Log.WriteException(ex.ToString());
                return false;
            }
        }

        public void Query()
        {
            lock (syncState)
            {
                bool bRet = false;
                try
                {
                    Log.WriteAsync("开始查询待清理记录...");                   
                    _status = OperateStatus.Query;
                    UpdateStatusIcon(_status);
                    bRet = OnPreparing();
                }
                catch (Exception ex)
                {
                    UpdateRemoveState("查询过程发生了异常.");
                    Log.WriteException(ex.ToString());
                    _status = OperateStatus.QueryFailed;
                }
                finally
                {
                    _status = bRet ? OperateStatus.Ready : OperateStatus.QueryFailed;
                    AfterQuery();
                }
            }
        }

        private bool WaittingForReady()
        {
            if (_status == OperateStatus.None
                || _status == OperateStatus.Finished)
            {
                Query();
                return WaittingForReady();
            }          
            if (_status == OperateStatus.Ready)
            {
                return true;
            }
            else if (_status == OperateStatus.QueryFailed)
            {
                Log.WriteAsync("查询失败，终止清理");
                return false;
            }
            else if (_status == OperateStatus.Running)
            {
                Log.WriteAsync("查询失败，终止清理");
                return false;
            }
            else if (_status == OperateStatus.Query)
            {
                if (SpinWait.SpinUntil(() => _status != OperateStatus.Query, 3000))
                {
                    if (_status == OperateStatus.QueryFailed)
                    {
                        return false;
                    }
                    if (_status == OperateStatus.Ready)
                    {
                        return true;
                    }
                    else
                    {
                        Log.WriteAsync("其它错误");
                        return false;
                    }
                }
                else
                {
                    Log.WriteAsync("等待查询超时");
                    return false;
                }
            }
            else
            {
                Log.WriteAsync("其它错误");
                return false;
            }
        }

        /// <summary>
        /// 执行清理的过程
        /// </summary>
        /// <returns>指示清理过程是否完整进行，中途中断返回false, 否则true</returns>
        private bool OnClearing()
        {
            try
            {
                string strLog = "";              
                for (int i = 0; i < listRemoveFolders.Count; i++)
                {
                    if (_bCancellTaskFlag)
                    {
                        WriteLog("清理被人为取消中断");
                        return false;
                    }
                    UpdateRemoveState("正在删除目录" + listRemoveFolders[i]);
                    Directory.Delete(listRemoveFolders[i], true);
                    strLog = listRemoveFolders[i] + "已经删除!";
                    UpdateTextBox(strLog);
                    WriteLog(strLog);
                    Thread.Sleep(1000);
                }
                return true;
            }
            catch (Exception ex)
            {
                UpdateRemoveState("清理过程发生了异常.");
                Log.WriteException(ex.ToString());
                _status = OperateStatus.Exception;
                return false;
            }        
        }

        public void CancellClearing()
        {
            if (_status == OperateStatus.Running)
            {
                _status = OperateStatus.Cancell;
                _bCancellTaskFlag = true;
                _strMessage = "用户中断了清理过程";
                Log.WriteAsync(_strMessage);
            }
        }

        public void Clear()
        {
            lock(syncState)
            {
                Log.WriteAsync("开始准备清理...");
                if (_status != OperateStatus.Query && _status != OperateStatus.Running)
                {
                    _status = OperateStatus.None;
                }
                if (!WaittingForReady())
                {
                    _strMessage = "清理意外结束";                   
                    Log.WriteAsync(_strMessage);
                    AfterClear();
                    return;
                }
                if (!GetCleaningPermit())
                {                   
                    _strMessage = "用户人为取消了清理";                   
                    Log.WriteAsync(_strMessage);
                    AfterClear();
                    return;
                }
                try
                {        
                    if(!_option.ExecuteWithSilence)
                    {
                        ShowWindow();
                    }
                    _status = OperateStatus.Running;
                    UpdateStatusIcon(_status);
                    OpenLogWriter();
                    Log.WriteAsync("开始正式清理...");
                    if (OnClearing())
                    {
                        _status = OperateStatus.Finished;
                        _strMessage = "清理已完成";
                        Log.WriteAsync(_strMessage);           
                    }                   
                }
                catch (Exception ex)
                {
                    _strMessage = "清理过程发生了异常:" + ex.Message;
                    Log.WriteException(ex.ToString());
                    _status = OperateStatus.Exception;
                }
                finally
                {
                    _bCancellTaskFlag = false;
                    AfterClear();
                    CloseLogWriter();
                }
            }       
        }

    }
}
